﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;

namespace FXnaEngine.Components
{
   public class FCameraComponent:FComponent
    {


       public FCameraComponent(FEntity parent)
           : base(parent)
       {



           this.viewFrustum = new BoundingFrustum(this.viewMatrix * this.projectionMatrix);

 

       }





       Color backgroundColor= Color.AliceBlue;

       /// <summary>
       /// 渲染的背景色
       /// </summary>
       public Color BackgroundColor
       {
           get { return backgroundColor; }
           set { backgroundColor = value; }
       }



       /// <summary>
       /// Camera's aspect ratio (used for <see cref="projectionMatrix"/>)
       /// </summary>
       public float AspectRatio
       {
           get { return this.aspectRatio; }
           set { this.aspectRatio = value; }
       }
       private float aspectRatio = 1.33333f;




       /// <summary>
       /// Camera's Field-of-view (Degrees). Field of view determines the angle of the camera's
       /// vision. Most FPS style games use between 70-110 degrees.
       /// </summary>
       /// <exception cref="ArgumentOutOfRangeException">Thrown if a <see cref="FOV"/> value is too high or less than or
       /// equal to the float.Epsilon."/></exception>
       public float FOV
       {
           protected get { return this.fov; }
           set
           {
               if (value < float.Epsilon)
               {
                   throw new ArgumentOutOfRangeException("FOV (field of view) cannot be zero or a negative value");
               }

               if (value > QSConstants.MaxFOV)
               {
                   throw new ArgumentOutOfRangeException("FOV (field of view) cannot be greater than " + QSConstants.MaxFOV + "degrees");
               }

               this.fov = value;
               // Set hasChanged flag to true (if we use a bool)

               // Update projection matrix
           }
       }
       private float fov = QSConstants.DefaultFOV;



       ProjectionMode projection   = ProjectionMode.Perspective;


       public ProjectionMode Projection
       {
           get { return projection; }
           set { projection = value; }
       }




       /// <summary>
       /// Camera's near plane distance. The camera will only draw things between the near and far planes.
       /// The camera's bounding frustum near-plane is based on this value as well.
       /// </summary>
       /// <exception cref="ArgumentOutOfRangeException">Thrown if a <see cref="NearPlane"/> value is too low or greater than or
       /// equal to the far-plane distance."/></exception>
       protected float NearPlane
       {
           get { return this.nearPlane; }
           set
           {
               if (value >= this.farPlane)
               {
                   throw new ArgumentOutOfRangeException("Near-plane distance cannot be greater than or equal to the far-plane distance");
               }

               if (value < QSConstants.MinNearPlane)
               {
                   throw new ArgumentOutOfRangeException("Near-plane distance cannot be less than " + QSConstants.MinNearPlane);
               }

               this.nearPlane = value;
               // Set hasChanged flag to true (if we use a bool)

               // Update projection matrix
           }
       }
       private float nearPlane = QSConstants.DefaultNearPlane;

       /// <summary>
       /// Camera's far plane distance. The camera will only draw things between the near and far planes.
       /// The camera's bounding frustum far-plane is based on this value as well.
       /// </summary>
       /// <exception cref="ArgumentOutOfRangeException">Thrown if a <see cref="FarPlane"/> value is too great or less than or
       /// equal to the near-plane distance."/></exception>
       public float FarPlane
       {
           protected get { return this.farPlane; }
           set
           {
               if (value <= this.nearPlane)
               {
                   throw new ArgumentOutOfRangeException("Far-plane distance cannot be less than or equal to the near-plane distance");
               }

               if (value > QSConstants.MaxFarPlane)
               {
                   throw new ArgumentOutOfRangeException("Far-plane distance cannot be greater than " + QSConstants.MaxFarPlane);
               }

               this.farPlane = value;
               // Set hasChanged flag to true (if we use a bool)

               // Update projection matrix
           }
       }
       private float farPlane = QSConstants.DefaultFarPlane;








       /// <summary>
       /// Holds projection-matrix information.
       /// </summary>        
       public Matrix ProjectionMatrix
       {
           get { return this.projectionMatrix; }
       }
       public Matrix projectionMatrix = Matrix.Identity;

       /// <summary>
       /// Holds view-matrix information.
       /// </summary>        
       public Matrix ViewMatrix
       {
           get { return this.viewMatrix; }
       }
       public Matrix viewMatrix = Matrix.Identity;

       /// <summary>
       /// Holds a view-frustum.
       /// </summary>
       public BoundingFrustum ViewFrustum
       {
           get { return this.viewFrustum; }
           set { this.viewFrustum = value; }
       }
       private BoundingFrustum viewFrustum;

       #region 对外方法

       /// <summary>
       /// Tests whether a bounding sphere is within the viewing frustum of the current active camera
       /// </summary>
       /// <param name="boundingVolume"></param>
       /// <returns></returns>
       protected virtual bool IsWithinViewFrustum(BoundingSphere boundingVolume)
       {

          return this.viewFrustum.Intersects(boundingVolume);

          
       }


       #endregion


       #region 过程控制

       public override void Update(GameTime gameTime)
       {
           base.Update(gameTime);

           FTransformComponent tran = this.ParentEntity.Transform;

           // Compute view matrix
           this.viewMatrix = Matrix.CreateLookAt(tran.Position,
                                                 tran.Position + tran.Orientation.Forward,
                                                 tran.Orientation.Up);




           this.projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(fov), this.aspectRatio,
                                                                  this.nearPlane, this.farPlane);
           



           this.viewFrustum.Matrix = this.viewMatrix * this.projectionMatrix;

       




       }


       public override bool ExecuteMessage(IMessage message)
       {


           return false;

       }

        #endregion




    }
}
